package codechicken.wirelessredstone.core;

import java.io.*;
import java.util.HashMap;
import java.util.Iterator;

import net.minecraft.src.*;

public class PacketRedstoneEther extends Packet
{
	public PacketRedstoneEther()
	{
		incoming = true;
		type = 0;
		isChunkDataPacket = false;
	}
	
	public PacketRedstoneEther(int i)
	{
		incoming = false;
		this.type = i;
		isChunkDataPacket = false;
		
		dataarrayout = new ByteArrayOutputStream();
		dataout = new DataOutputStream(dataarrayout);
	}
	
	public static void assignHandler(int[] range, IWirelessPacketHandler handler)
	{
		if(range.length != 2)
		{
			ModLoader.ThrowException("Wireless Packet", new Exception("Id Range length != 2"));
		}
		if(idhandlermap.containsValue(handler))
		{
			ModLoader.ThrowException("Wireless Packet", new Exception("Handler Already Set"));
		}
		
		idhandlermap.put(range, handler);
	}
	
	public int getType()
	{
		return type;
	}
	
	public void readPacketData(DataInputStream datainputstream) throws IOException
	{
		if(!incoming)
		{
			ModLoader.ThrowException("Wireless Packet", new Exception("Tried to read from an outgoing packet"));
			return;
		}
		
		type = datainputstream.readByte();
		
		int datasize = datainputstream.readShort();
		dataarrayin = new byte[datasize];
		datainputstream.read(dataarrayin, 0, datasize);
		datain = new DataInputStream(new ByteArrayInputStream(dataarrayin));
	}

	public void writePacketData(DataOutputStream dataoutputstream) throws IOException
	{
		if(type == 0)
		{
			ModLoader.ThrowException("Wireless Packet", new Exception("Type not set"));
			return;
		}
		if(incoming)
		{
			ModLoader.ThrowException("Wireless Packet", new Exception("Tried to write an incoming packet"));
			return;
		}
		
		dataoutputstream.write(type & 0xFF);
		dataoutputstream.writeShort(dataout.size());
		dataarrayout.writeTo(dataoutputstream);
	}
	
	private IWirelessPacketHandler getPacketHandler()
	{
		for(Iterator<int[]> iterator = idhandlermap.keySet().iterator(); iterator.hasNext();)
		{
			int[] range = iterator.next();
			if(range[0] <= type && range[1] >= type)
			{
				return idhandlermap.get(range);
			}
		}

		ModLoader.ThrowException("Wireless Packet", new Exception("No Id handler for id "+type));
		return null;
	}

	public void processPacket(NetHandler nethandler)
	{
		CoreProxy.HandlePacket(this, nethandler, getPacketHandler());
	}
	
	public void writeBoolean(boolean b)
	{
		try
		{
			dataout.writeBoolean(b);
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
	}
	
	public void writeByte(byte b)
	{
		try
		{
			dataout.writeByte(b);
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
	}
	
	public void writeShort(short s)
	{
		try
		{
			dataout.writeShort(s);
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
	}
	
	public void writeInt(int i)
	{
		try
		{
			dataout.writeInt(i);
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
	}
	
	public void writeFloat(float f)
	{
		try
		{
			dataout.writeFloat(f);
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
	}
	
	public void writeDouble(double d)
	{
		try
		{
			dataout.writeDouble(d);
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
	}
	
	public void writeLong(long l)
	{
		try
		{
			dataout.writeLong(l);
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
	}
		
	public void writeByteArray(byte[] barray)
	{
		try
		{
			dataout.write(barray);
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
	}
	
	public void writeCoord(int x, int y, int z)
	{
		writeInt(x);
		writeByte((byte) y);
		writeInt(z);
	}
	
	public void writeCoord(BlockCoord node)
	{
		writeCoord(node.x, node.y, node.z);
	}
	
	public void writeString(String info)
	{
		try
		{
			dataout.writeShort(info.length());
			dataout.write(info.getBytes("US-ASCII"));
		}
		catch(IOException e)
		{
			e.printStackTrace();
		}
	}
	
	public boolean readBoolean()
	{
		try
		{
			return datain.readBoolean();
		}
		catch(IOException e)
		{
			e.printStackTrace();
			return false;
		}
	}
	
	public byte readByte()
	{
		try
		{
			return datain.readByte();
		}
		catch(IOException e)
		{
			e.printStackTrace();
			return 0;
		}
	}
	
	public short readShort()
	{
		try
		{
			return datain.readShort();
		}
		catch(IOException e)
		{
			e.printStackTrace();
			return 0;
		}
	}
	
	public int readInt()
	{
		try
		{
			return datain.readInt();
		}
		catch(IOException e)
		{
			e.printStackTrace();
			return 0;
		}
	}
	
	public float readFloat()
	{
		try
		{
			return datain.readFloat();
		}
		catch(IOException e)
		{
			e.printStackTrace();
			return 0;
		}
	}
	
	public double readDouble()
	{
		try
		{
			return datain.readDouble();
		}
		catch(IOException e)
		{
			e.printStackTrace();
			return 0;
		}
	}
	
	public long readLong()
	{
		try
		{
			return datain.readLong();
		}
		catch(IOException e)
		{
			e.printStackTrace();
			return 0;
		}
	}
	
	public BlockCoord readCoord()
	{
		return new BlockCoord(readInt(), readByte() & 0xFF, readInt());
	}
	
	public byte[] readByteArray(int length)
	{
		try
		{
			byte[] barray = new byte[length];
			datain.read(barray, 0, length);
			return barray;
		}
		catch(IOException e)
		{
			e.printStackTrace();
			return null;
		}
	}
	
	public byte[] readAll()
	{
		return dataarrayin;
	}
	
	public String readString()
	{
		try
		{
			int length = datain.readShort();
			return new String(readByteArray(length), "US-ASCII");
		}
		catch(IOException e)
		{
			e.printStackTrace();
			return null;
		}
		
	}
	
	public int getPacketSize()
	{
		return (incoming ? dataarrayin.length : dataout.size()) + 3;
	}
	
	private int type;
	
	private ByteArrayOutputStream dataarrayout;
	private DataOutputStream dataout;
	
	private DataInputStream datain;
	private byte[] dataarrayin;
	
	private boolean incoming;
	
	private static HashMap<int[], IWirelessPacketHandler> idhandlermap = new HashMap<int[], IWirelessPacketHandler>();
}
